using System.Diagnostics.CodeAnalysis;

namespace Viyi.Util.Linq;

public static partial class EnumerableExtensions {
    [return: NotNullIfNotNull(nameof(source))]
    public static T[]? AsToArray<T>(this IEnumerable<T> source, bool isNullAsEmpty = false) {
        if (source == null) {
            return isNullAsEmpty ? Array.Empty<T>() : null;
        }

        return source is T[] array ? array : source.ToArray();
    }

    [return: NotNullIfNotNull(nameof(source))]
    public static List<T>? AsToList<T>(this IEnumerable<T> source, bool isNullAsEmpty = false) {
        if (source == null) {
            return isNullAsEmpty ? new List<T>() : null;
        }
        return source is List<T> list ? list : source.ToList();
    }

    public static IEnumerable<T> NotNull<T>(this IEnumerable<T?> source) =>
        source.Where(it => it != null).Cast<T>();

    public static IEnumerable<T> NotNull<T, F>(this IEnumerable<T> source, Func<T, F> selector) =>
        source.Where(it => selector(it) != null);

    public static IEnumerable<T> WhereNot<T>(this IEnumerable<T> source, Func<T, bool> predicate) =>
        source.Where(it => !predicate(it));

    public static IEnumerable<T> Peek<T>(this IEnumerable<T> source, Action<T> consumer) =>
        source.Select(it => {
            consumer(it);
            return it;
        });

    public static R? FindBy<T, R>(this IEnumerable<T> source, Func<T, R> selector, Func<R, bool> predicate) {
        return source.Select(selector).FirstOrDefault(predicate);
    }
}
